#pragma once

#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

template<class T>
class RingQueue
{
private:
    void Lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void UnLock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
public:
    RingQueue(int capacity)
        :_capacity(capacity), _ringQueue(capacity), _productIdx(0), _consumIdx(0)
    {
        sem_init(&_roomSem, 0, capacity);
        sem_init(&_dataSem, 0, 0);
        pthread_mutex_init(&_productMutex, nullptr);
        pthread_mutex_init(&_consumMutex, nullptr);
    }

    void Enqueue(const T& in)
    {
        //先买票再排队
        P(_roomSem);
        Lock(_productMutex);

        _ringQueue[_productIdx++] = in;
        _productIdx %= _capacity;

        UnLock(_productMutex);
        V(_dataSem);
    }

    void Pop(T* out)
    {
        //先买票再排队
        P(_dataSem);
        Lock(_consumMutex);

        *out = _ringQueue[_consumIdx++];
        _consumIdx %= _capacity;

        UnLock(_consumMutex);
        V(_roomSem);
    }

    ~RingQueue()
    {
        sem_destroy(&_roomSem);
        sem_destroy(&_dataSem);
        pthread_mutex_destroy(&_productMutex);
        pthread_mutex_destroy(&_consumMutex);
    }

private:
    int _capacity;
    std::vector<T> _ringQueue;

    int _productIdx; // 生产者所在位置
    int _consumIdx; // 消费者所在位置

    sem_t _roomSem; //空间信号量 生产者
    sem_t _dataSem; //数据信号量 消费者
   
    pthread_mutex_t _productMutex;  //生产者和生产者之间
    pthread_mutex_t _consumMutex;  //消费者和消费者之间
};